package com.test.demo.config;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSON;
import com.test.demo.common.CommonParam;
import com.test.demo.common.Constants;
import com.test.demo.common.result.Result;
import com.test.demo.common.result.ResultCode;
import com.test.demo.utils.JwtUtil;
import com.test.demo.utils.NetworkUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class Interceptor implements HandlerInterceptor {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String requestUrl = request.getRequestURI();
        String ipAddress = NetworkUtil.getIpAddress(request);
        log.debug("此次访问的接口：{},ip:{}", requestUrl, ipAddress);
        CommonParam.remove();
        CommonParam.getInstance().setBeginTime(new Date());
        CommonParam.getInstance().setRequestUrl(requestUrl);
        //接口检验
        if (requestUrlConfirm(request, ipAddress)) {
            return true;
        }
        String token = request.getHeader("token");
        //开始校验token
        if (StringUtils.isBlank(token)) {
            return resultMessage(response, Result.fail(ResultCode.HEADER_INVALID.code, ResultCode.HEADER_INVALID.msg));
        }
        return checkToken(response, token);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView modelAndView) {
        Date beginTime = CommonParam.getInstance().getBeginTime();
        double duration = (System.currentTimeMillis() - beginTime.getTime()) / 1000.000;
        if (duration > 3) {
            String method = ((HandlerMethod) o).getMethod().toString().split("\\s+")[2];
            log.info(method.substring(0, method.indexOf('(')) + " " + " - execution time：" + String.format("%.3f", duration) + "s");
        }
    }

    /**
     * 接口检验
     *
     * @param request
     * @return
     */
    private boolean requestUrlConfirm(HttpServletRequest request, String ipAddress) {
        //不校验token的接口统一跳过
        String requestUrl = request.getRequestURI();
        if (requestUrl.endsWith("register") ||
                requestUrl.endsWith("getAuthCodeImg")||
                requestUrl.endsWith("sendSms")
        ) {
            return true;
        } else if (requestUrl.endsWith("test")
        ) {
            if ("localhost".equals(ipAddress) || "127.0.0.1".equals(ipAddress) || ipAddress.startsWith("10") || ipAddress.startsWith("172.16") || ipAddress.startsWith("192.168")) {
                return true;
            } else {
                log.error("不是内部IP访问：" + ipAddress + ",接口：" + requestUrl);
                return false;
            }
        }
        return false;
    }

    /**
     * 检查token
     *
     * @param response
     * @param token
     * @return
     * @throws Exception
     */
    private boolean checkToken(HttpServletResponse response, String token) {
        //如果有传token，解密token
        Claims verifyToken = JwtUtil.parseJwt(token);
        if (verifyToken == null) {
            log.error("token不匹配");
            return resultMessage(response, Result.fail(ResultCode.TOKEN_INVALID.code, ResultCode.TOKEN_INVALID.msg));
        }
        Long userId = Convert.toLong(verifyToken.get("userId"));
        CommonParam.getInstance().setUserId(userId);
        ;

        String appRedisToken = (String) redisTemplate.opsForValue().get(Constants.APP_TOKEN + userId);
        if (StringUtils.isBlank(appRedisToken) || !appRedisToken.equals(token)) {
            log.error("token过期");
            return resultMessage(response, Result.fail(ResultCode.TOKEN_INVALID.code, ResultCode.TOKEN_INVALID.msg));
        }
        redisTemplate.opsForValue().set(Constants.APP_TOKEN + userId, token, 15, TimeUnit.DAYS);
        return true;
    }

    /**
     * token
     *
     * @param response
     * @return
     */
    private boolean resultMessage(HttpServletResponse response, Result result) {
        response.setHeader("Content-Type", "application/json;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        try (ServletOutputStream writer = response.getOutputStream()) {
            writer.write(JSON.toJSONBytes(result));
        } catch (IOException e) {
            log.error("response error", e);
        }
        return false;
    }


}
